package com.digua.base.socket

import com.digua.base.socket.ReconnectManager.OnConnectListener
import com.digua.base.util.LogUtil
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.RejectedExecutionException


class DefaultReconnectManager : ReconnectManager {

    /**
     * 重连锁
     */
    private val BLOCK = Object()
    private var webSocketManager: WebSocketManager
    private var onDisconnectListener: OnConnectListener

    //是否正在重连
    @Volatile
    private var reconnecting = false

    //被销毁
    @Volatile
    private var destroyed = false

    //是否需要停止重连
    @Volatile
    private var needStopReconnect = false

    //是否已链接
    @Volatile
    private var connected = false

    private var reconnectCount = 1
    private var finishCount = 1

    private val singleThreadPool: ExecutorService? = Executors.newSingleThreadExecutor()

    constructor(webSocketManager: WebSocketManager, onDisconnectListener: OnConnectListener) {
        this.webSocketManager = webSocketManager
        this.onDisconnectListener = onDisconnectListener
        reconnecting = false
        destroyed = false
    }

    override fun reconnecting() = reconnecting

    override fun startReconnect() {
        if (reconnecting) {
            LogUtil.d("重连中，请匆重复操作.")
            return
        }
        if (destroyed) {
            LogUtil.d("重连管理已经被销毁")
            return
        }
        needStopReconnect = false
        reconnecting = true
        try {
            singleThreadPool!!.execute(getReconnectRunnable())
        } catch (e: RejectedExecutionException) {
            LogUtil.e("线程队列已满，无法执行此次任务。", e)
            reconnecting = false
        }
    }

    private fun getReconnectRunnable(): Runnable {
        return Runnable {
            if (destroyed || needStopReconnect) {
                reconnecting = false
                return@Runnable
            }
            LogUtil.d("开始重连:$reconnectCount")
            reconnectCount++
            reconnecting = true
            connected = false
            try {
                val count = webSocketManager.setting?.reconnectFrequency ?: 10
                for (i in 0 until count) {
                    LogUtil.d("第${i + 1}次重连")
                    webSocketManager.reconnectOnce()
                    var isBreak = false
                    synchronized(BLOCK) {
                        try {
                            BLOCK.wait(webSocketManager.setting?.connectTimeout ?: 0)
                            if (connected) {
                                LogUtil.d("重链接一次成功!")
                                onDisconnectListener.onConnected()
                                return@Runnable
                            }
                            if (needStopReconnect) isBreak = true
                        } catch (e: InterruptedException) {
                            isBreak = true
                        }
                    }
                    if (isBreak) break
                }
                //重连失败
                LogUtil.d("重链接一次失败!")
                onDisconnectListener.onDisconnect()
            } finally {
                LogUtil.d("重连结束:$finishCount")
                finishCount++
                reconnecting = false
                LogUtil.d("reconnecting = false")
            }
        }
    }

    override fun stopReconnect() {
        needStopReconnect = true
        singleThreadPool?.shutdownNow()
    }

    override fun onConnected() {
        connected = true
        synchronized(BLOCK) {
            LogUtil.d("onConnected()->BLOCK.notifyAll()")
            BLOCK.notifyAll()
        }
    }

    override fun onConnectError(th: Throwable?) {
        connected = false
        synchronized(BLOCK) {
            LogUtil.d("onConnectError(Throwable)->BLOCK.notifyAll()")
            BLOCK.notifyAll()
        }
    }

    /**
     * 销毁资源，并停止重连
     */
    override fun destroy() {
        destroyed = true
        stopReconnect()
        //mWebSocketManager = null
    }

    override fun isConnected() = connected
    override fun isReconnecting() = reconnecting
}